package com.wxw.BaseLibrary.tool;

/**
 * Created by david on 14-3-11.
 */

import android.util.Log;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import java.io.*;
import java.util.ArrayList;

public class XmlHelper {
    private Document xmlDoc=null;
    private String xmlFile="";
    public static String TAG = "XmlHelper";

    public XmlHelper(String xmlFile)
    {
        try {
            InputStream istream=new FileInputStream(xmlFile);
            DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
            DocumentBuilder db=dbf.newDocumentBuilder();
            xmlDoc=db.parse(istream);
            this.xmlFile = xmlFile;
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ParserConfigurationException pe){
            pe.printStackTrace();
        } catch (SAXException se) {
            se.printStackTrace();
        } catch (IOException ie) {
            ie.printStackTrace();
        }

    }

    public XmlHelper(Document doc){
        xmlDoc=doc;
    }

    /**
     * @return the xmlDoc
     */
    public Document getXmlDoc() {
        return xmlDoc;
    }

    public String getValueByPath(String path, String defValue){
        NodeList nodeList = getNodesByPath(path);
        if (nodeList==null || nodeList.getLength()<=0){
            appendPathByPath(xmlDoc.getDocumentElement(), path);
            writeValueByPath(path, defValue);
            return defValue;
        } else {
            return nodeList.item(0).getTextContent();
        }
    }

    public NodeList getNodesByPath(String path){
        return getNodesByPath(xmlDoc.getDocumentElement(), path);
    }

    public NodeList getNodesByPath(Node parent, String path){
        if (path.startsWith("/")) {
            path=path.substring(1);
        }
        String[] paths = path.split("\\/");
        Node node=parent;
        int i=0;
        for (;i<paths.length-1;i++){
            if (!node.hasChildNodes()) {
                break;
            }
            Node temp=getChildByName(node, paths[i]);
            if (temp==null) {
                return null;
            }
            node=temp;
        }
        if (i<paths.length-2) {
            return null;
        }
        return getChildsByName(node, paths[paths.length-1]);
    }

    public Node getChildByName(Node parent, String name){
        if (!parent.hasChildNodes()) {
            return null;
        }
        NodeList childs = parent.getChildNodes();

        for (int i=0;i<childs.getLength();i++){
            if (childs.item(i).getNodeType()==Node.ELEMENT_NODE && childs.item(i).getNodeName().equals(name)) {
                return childs.item(i);
            }
        }
        return null;
    }

    public NodeList getChildsByName(Node parent, String name){
        if (!parent.hasChildNodes()) {
            return null;
        }
        NodeList childs = parent.getChildNodes();
        MDSNodeList nodeList = new MDSNodeList();
        for (int i=0;i<childs.getLength();i++){
            if (childs.item(i).getNodeType()==Node.ELEMENT_NODE && childs.item(i).getNodeName().equals(name)) {
                nodeList.add(childs.item(i));
            }
        }
        return nodeList;
    }

    public String getAttributeValue(Node node, String attrName){
        if (node!=null && node.hasAttributes()){
            Node attr= node.getAttributes().getNamedItem(attrName);
            return attr==null?"":attr.getNodeValue();
        }
        return "";
    }

    /**
     * 通过XPath表达式获取Node对象列表
     * @param xpath
     * @return
     */
    public NodeList getNodeListByXPath(String xpath, NamespaceContext namespaceContext){
        XPath xpath1 = XPathFactory.newInstance().newXPath();
        NodeList nodes=null;
        try {
            if (namespaceContext!=null) {
                xpath1.setNamespaceContext(namespaceContext);
            }
            XPathExpression expression = xpath1.compile(xpath);
            nodes = (NodeList)expression.evaluate(xmlDoc, XPathConstants.NODESET);
        } catch (XPathExpressionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
        return nodes;
    }

    /**
     * 通过XPath表达式获取Node对象的值
     * @param xpath
     * @return
     */
    public String getNodeValueByXPath(String xpath){
        XPath xpath1 = XPathFactory.newInstance().newXPath();
        String value = "";
        try {
            value = xpath1.evaluate(xpath, xmlDoc);
        } catch (XPathExpressionException e) {
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
        return value;
    }

    public boolean appendNodeByPath(String path, String nodeName, String nodeContent){
        return appendNodeByPath(path, createNode(nodeName, nodeContent, getXmlDoc()));
    }

    public boolean appendNodeByPath(String path, Node node){
        try{
            NodeList nodeList = getNodesByPath(path);
            if (nodeList == null || nodeList.getLength() <= 0) {
                return false;
            }
            appendNodeToParent(nodeList.item(0), node);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
        return false;
    }

    public boolean appendNodeByXPath(String xpath, String nodeName, String nodeContent){
        return appendNodeByXPath(xpath, createNode(nodeName, nodeContent, getXmlDoc()));
    }

    public boolean appendNodeByXPath(String xpath, Node node){
        try{
            NodeList nodeList = getNodeListByXPath(xpath, null);
            if (nodeList == null || nodeList.getLength() <= 0) {
                return false;
            }
            appendNodeToParent(nodeList.item(0), node);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
        return false;
    }

    public void appendNodeToParent(Node parent, Node node){
        try{
            if (!parent.hasChildNodes()) {
                parent.appendChild(node);
            } else {
                NodeList nchildlist = parent.getChildNodes();
                boolean b = true;
                for (int i=0;i<nchildlist.getLength();i++){
                    if (nchildlist.item(i).getNodeName().equals(node.getNodeName())){
                        b=false;
                        nchildlist.item(i).setTextContent(node.getTextContent());
                        break;
                    }
                }
                if (b) {
                    parent.appendChild(node);
                }
            }
//            write2Xml(xmlDoc, xmlFile);
        }catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
    }

    public void writeValueByXpath(String xpath, String value){
        try{
            NodeList nodeList = getNodeListByXPath(xpath, null);
            if(nodeList!=null && nodeList.getLength()>0){
                Node node = nodeList.item(0);
                if (node.getNodeType()== Node.ELEMENT_NODE){
                    Element element = (Element)node;
                    if (element.getAttributeNode("Value")!=null) {
                        element.setAttribute("Value", value);
                    } else {
                        element.setTextContent(value);
                    }
                    File file = new File(xmlFile);
                    if (!file.exists()) {
                        file.createNewFile();
                    }
                    write2Xml(xmlDoc, file);
                }
            }
        } catch (Exception e){
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
    }

    public void writeValueByPath(String path, String value){
        try{
            NodeList nodeList = getNodesByPath(path);
            if(nodeList!=null && nodeList.getLength()>0){
                Node node = nodeList.item(0);
                if (node.getNodeType()== Node.ELEMENT_NODE){
                    Element element = (Element)node;
                    if (element.getAttributeNode("Value")!=null) {
                        element.setAttribute("Value", value);
                    } else {
                        element.setTextContent(value);
                    }
                    File file = new File(xmlFile);
                    if (!file.exists()) {
                        file.createNewFile();
                    }
                    write2Xml(xmlDoc, file);
                }
            }else{

            }
        } catch (Exception e){
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
        }
    }

    public void appendPathByPath(String parentPath, String path){
        NodeList nodeList = getNodesByPath(parentPath);
        if (nodeList==null||nodeList.getLength()<=0) {
            return;
        }
        appendPathByPath(nodeList.item(0), path);
    }

    public void appendPathByPath(Node parent, String path){
        NodeList nodeList = getNodesByPath(parent, path);
        if (nodeList!=null && nodeList.getLength()>0) {
            return;
        }
        if (path.startsWith("/")) {
            path=path.substring(1);
        }
        String[] paths = path.split("\\/");
        Node tParent = parent;
        for (int i=0;i<paths.length;i++){
            if (!tParent.hasChildNodes()){
                appendNodeToParent(tParent, createNode(paths[i], null, getXmlDoc()));
                tParent = tParent.getFirstChild();
            } else {
                NodeList nodeList1 = tParent.getChildNodes();
                boolean childExist = false;
                for (int j=0;j<nodeList1.getLength();j++){
                    if (nodeList1.item(j).getNodeName().equals(paths[i])){
                        tParent = nodeList1.item(j);
                        childExist = true;
                        break;
                    }
                }
                if (!childExist){
                    appendNodeToParent(tParent, createNode(paths[i], null, getXmlDoc()));
                    tParent = tParent.getFirstChild();
                }
            }
        }
    }

    public static Document createDocument(String root){
        try{
            DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
            DocumentBuilder db=dbf.newDocumentBuilder();
            Document document = db.newDocument();
            document.appendChild(document.createElement(root));
            return document;
        } catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
            return null;
        }
    }

    public static Node createNode(String name, Document document){
        try {
            return document.createElement(name);
        } catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
            return null;
        }
    }

    public static Node createNode(String name, String content, Document document){
        Node node = createNode(name, document);
        if (node==null) {
            return null;
        }
        if (content!=null) {
            node.setTextContent(content);
        }
        return node;
    }

    public static Attr createAttr(String name, String value, Document document){
        try {
            Attr attr = document.createAttribute(name);
            attr.setValue(value);
            return attr;
        } catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+ e.getMessage());
            return null;
        }
    }

    public static boolean write2Xml(Document document, String fileName){
        return write2Xml(document, new File(fileName));
    }

    public static boolean write2Xml(Document document, File file) {
        // 创建转化工厂
        TransformerFactory factory = TransformerFactory.newInstance();
        // 创建转换实例
        try {
            if (!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }

            Transformer transformer = factory.newTransformer();

            // 将建立好的DOM放入DOM源中
            DOMSource domSource = new DOMSource(document);

            // 创建输出流
            StreamResult result = new StreamResult(file);

            // 开始转换
            transformer.transform(domSource, result);
            return true;

        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+e.getMessage());
            return false;
        } catch (TransformerException e) {
            e.printStackTrace();
            Log.e(TAG, "Class:XmlHelper,Msg:"+e.getMessage());
            return false;
        } catch (Exception e){
            Log.e(TAG, "Class:XmlHelper,Msg:"+e.getMessage());
            return false;
        }
    }

    public class MDSNodeList implements NodeList{
        private ArrayList<Node> childs=new ArrayList<Node>();

        @Override
        public Node item(int i) {
            return childs.size()<=0 || i>childs.size()-1 || i<0?null:childs.get(i);
        }

        @Override
        public int getLength() {
            return childs.size();
        }

        public void add(Node node){
            childs.add(node);
        }
    }
}
